
// ===============================================================================================================
// -*- C++ -*-
//
// RefPtr.hpp - A smart pointer container for handling referenced counted objects.
//
// Copyright (c) 2011 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#ifndef __REF_PTR_HPP__
#define __REF_PTR_HPP__

///
/// RefPtr -- Smart pointer for handling referenced counted objects.
/// \note This template class only works with objects derived from the ReferenceCountable interface.
///
template<typename T> class RefPtr {

public:

	/// Construct from object pointer. Takes ownership of the pointer, does NOT call AddRef()!
	inline RefPtr(T * object = 0)
	: data(object)
	{
	}

	/// Copy constructor. Share pointer. Calls AddRef().
	inline RefPtr(const RefPtr<T> & rhs)
	: data(rhs.data)
	{
		if (data)
		{
			data->AddRef();
		}
	}

	/// Assignment operator. Takes ownership of the pointer. Release previous, does NOT call AddRef()!
	inline RefPtr<T> & operator = (T * object)
	{
		if (data != object)
		{
			T * tmp = data;
			data = object;

			if (tmp)
			{
				tmp->Release();
			}
		}
		return (*this);
	}

	/// Assignment operator. Share pointer. Release previous, call AddRef() on new object.
	inline RefPtr<T> & operator = (const RefPtr<T> & rhs)
	{
		if (data != rhs.data)
		{
			T * tmp = data;
			data = rhs.data;

			if (data)
			{
				data->AddRef();
			}
			if (tmp)
			{
				tmp->Release();
			}
		}
		return (*this);
	}

	/// Swap this and rhs.
	inline void Swap(RefPtr<T> & rhs)
	{
		if (data != rhs.data)
		{
			T * tmp = data;
			data = rhs.data;
			rhs.data = tmp;
		}
	}

	/// Giveup pointer ownership and return old pointer. Does NOT call Relsease()!
	inline T * GiveupOwnership(void)
	{
		T * tmp = data;
		data = 0;
		return (tmp);
	}

	/// Destructor releases the object.
	~RefPtr(void)
	{
		if (data)
		{
			data->Release();
			data = 0;
		}
	}

public:

	/// Return designated value. Cause an assertion if the pointer is null.
	inline T & operator *() const { return (*data); }

	/// Return pointer to class object. Cause an assertion if the pointer is null.
	inline T * operator->() const { return (data);  }

	/// Returns the stored pointer.
	inline T * Get(void) const { return (data); }

	/// Boolean operator to check if the pointer is valid.
	inline operator bool () const { return (data != 0); }

	/// Boolean operator to check if the pointer is not valid.
	inline bool operator!() const { return (data == 0); }

	/// Test if this pointer internal object is valid (not null).
	inline bool Valid(void) const { return (data != 0); }

	/// Equality operator.
	inline bool operator == (const RefPtr<T> & rhs) const { return (data == rhs.data); }

	/// Inequality operator.
	inline bool operator != (const RefPtr<T> & rhs) const { return (data != rhs.data); }

	/// Greater than operator.
	inline bool operator > (const RefPtr<T> & rhs) const { return (data > rhs.data); }

	/// Less than operator.
	inline bool operator < (const RefPtr<T> & rhs) const { return (data < rhs.data); }

	/// Greater equal operator.
	inline bool operator >= (const RefPtr<T> & rhs) const { return (data >= rhs.data); }

	/// Less equal operator.
	inline bool operator <= (const RefPtr<T> & rhs) const { return (data <= rhs.data); }

private:

	T * data;
};

#endif // __REF_PTR_HPP__